package be.redo.controller;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import be.redo.command.FlightSearchForm;
import be.redo.command.FoundFlights;
import be.redo.model.entities.Airport;
import be.redo.model.entities.Continent;
import be.redo.model.entities.Flight;
import be.redo.model.entities.Line;
import be.redo.model.entities.Region;
import be.redo.service.AirportService;
import be.redo.service.ContinentService;
import be.redo.service.FlightService;
import be.redo.service.LineService;
import be.redo.service.RegionService;

@SessionAttributes(BookingController.MY_FLIGHT_IDS)
@RequestMapping("/bookings")
@Controller
public class BookingController {
	final Logger logger = LoggerFactory.getLogger(this.getClass());

	public static final String MY_FLIGHT_IDS = "myFlightIds";
	@Autowired
	ContinentService continentService;
	@Autowired
	RegionService regionService;
	@Autowired
	AirportService airportService;
	@Autowired
	LineService lineService;
	@Autowired
	FlightService flightService;

	@RequestMapping(value = "searchForm", produces = "text/html")
	public String searchForm(Model uiModel, HttpServletRequest request) {
		logger.debug(request.getMethod() + " searchForm");

		createSessionAttributeMyFlightIds(uiModel);
		// TODO departureAirports ophalen van service
		FlightSearchForm flightSearchForm = new FlightSearchForm();
		flightSearchForm.setDepartureRegions(regionService.findAll());
		flightSearchForm.setDestinationRegions(regionService.findAll());
		// TODO airports ophalen moet via ajax gebeuren, niet all airports maar
		// alleen die
		// van de geselecteerde regio
		flightSearchForm.setDestiantions(airportService.findAll());
		flightSearchForm.setDepartures(airportService.findAll());
		uiModel.addAttribute("FlightSearchForm", flightSearchForm);
		return "bookings/searchForm";
	}

	@RequestMapping(value = "destinationsMap", produces = "text/html")
	public String destinationsMap(Model uiModel, HttpServletRequest request) {
		logger.debug(request.getMethod() + " destinationsMap");

		createSessionAttributeMyFlightIds(uiModel);
		return "bookings/destinationsMap";
	}

	@RequestMapping(value = "searchForm", params = "continent", produces = "text/html")
	public String continent(Model uiModel, Continent destinationContinent,
			HttpServletRequest request) {
		logger.debug(request.getMethod() + " searchForm "
				+ request.getQueryString());

		createSessionAttributeMyFlightIds(uiModel);
		FlightSearchForm flightSearchForm = new FlightSearchForm();
		// TODO laatst gebruikt continent uit de sessie halen en gebruiken als
		// departureContinent.
		List<Continent> departureContinents = continentService
				.findContinentsByNameLike("urop");
		List<Region> departureRegions = new ArrayList<Region>(1000);
		for (Continent departureContinent : departureContinents) {
			departureRegions.addAll(regionService
					.findRegionsByContinent(departureContinent));
		}
		flightSearchForm.setDepartureRegions(departureRegions);
		flightSearchForm.setDestinationRegions(regionService
				.findRegionsByContinent(destinationContinent));
		// TODO airports ophalen moet via ajax gebeuren, niet all airports maar
		// alleen die
		// van de geselecteerde regio
		// TODO verplaatsen naar AJAX call handlers.
		flightSearchForm.setDestiantions(airportService.findAll());
		flightSearchForm.setDepartures(airportService.findAll());
		uiModel.addAttribute("FlightSearchForm", flightSearchForm);

		return "bookings/searchForm";
	}

	/**
	 * @param uiModel
	 */
	private void createSessionAttributeMyFlightIds(Model uiModel) {
		if (!uiModel.containsAttribute(MY_FLIGHT_IDS)) {
			Set<Long> myFlightIds = new HashSet<Long>();
			uiModel.addAttribute(MY_FLIGHT_IDS, myFlightIds);
		}
	}

	@RequestMapping(value = "search", params = { "departure", "destination" }, produces = "text/html")
	public String findFlights(Model uiModel, @RequestParam String departure,
			@RequestParam String destination, HttpServletRequest request) {
		logger.debug(request.getMethod() + " search "
				+ request.getQueryString());

		Airport departureAirport = airportService
				.findAirportsByCodeEquals(departure);
		Airport destinationAirport = airportService
				.findAirportsByCodeEquals(destination);
		List<Line> lines = lineService.findLinesByDepartureAndDestination(
				departureAirport, destinationAirport);
		Set<Flight> flights = new HashSet<Flight>();
		Date now = new Date();
		for (Line line : lines) {
			flights.addAll(flightService
					.findFlightsByLineWhereDepartureIsLaterThan(line, now));
		}
		List<Flight> sortedFlights = new ArrayList<Flight>(flights);
		Collections.sort(sortedFlights, Flight.getPriceComparator());
		FoundFlights foundFlights = new FoundFlights();
		foundFlights.setDeparture(departureAirport);
		foundFlights.setDestination(destinationAirport);
		foundFlights.setFlights(sortedFlights);
		uiModel.addAttribute("foundFlights", foundFlights);
		return "bookings/discoveredFlights";
	}

	@RequestMapping(value = "orderflight", produces = "text/html")
	public String orderFlight(Model uiModel, @RequestParam Flight flight,
			@ModelAttribute(MY_FLIGHT_IDS) Set<Long> myFlightIds,
			HttpServletRequest request) {
		logger.debug(request.getMethod() + " orderflight"
				+ request.getQueryString());

		myFlightIds.add(flight.getFlightId());
		Set<Flight> myFlights = new HashSet<Flight>();
		for (long id : myFlightIds) {
			myFlights.add(flightService.read(id));
		}
		uiModel.addAttribute("myFlights", myFlights);
		return "bookings/basket";
	}
}
